<?php
/**
 * ProductRepo.php
 *
 * @copyright   2023 thingsworld.com.cn - All Rights Reserved
 * @link        http://thingsworld.com.cn/
 * @author      stiffer.chen <chenl@thingsworld.com.cn>
 * @created     2023-02-14 01:25:55
 * @modified    2023-02-14 01:25:55
 *
 */

namespace App\Repositories;

use App\Models\CityModel;
use App\Models\Customer;
use App\Models\DeptModel;
use App\Models\Event;
use App\Models\Product;
use App\Repositories\Product\QrCodeRepo;
use Carbon\Carbon;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;

class ProductRepo
{
    const IN_WARRANTY_CODE = 'in_warranty';
    const IN_WARRANTY_TITLE = '保内';
    const OUT_WARRANTY_CODE = 'out_warranty';
    const OUT_WARRANTY_TITLE = '保外';

    const WARRANTY_CODES = [
        self::IN_WARRANTY_CODE,
        self::OUT_WARRANTY_CODE
    ];

    const WARRANTY_TITLES = [
        self::IN_WARRANTY_TITLE,
        self::OUT_WARRANTY_TITLE
    ];

    const WARRANTY_TYPE_AT_CODE = 'at';
    const WARRANTY_TYPE_MT_CODE = 'mt';

    const WARRANTY_TYPE_AT_TITLE = '自动计算';
    const WARRANTY_TYPE_MT_TITLE = '手动添加';

    public static function params()
    {
        return [
            'warranty_status' => [
                [
                    'code' => self::IN_WARRANTY_CODE,
                    'title' => self::IN_WARRANTY_TITLE
                ],
                [
                    'code' => self::OUT_WARRANTY_CODE,
                    'title' => self::OUT_WARRANTY_TITLE
                ]
            ],
            'warranty_types' => [
                [
                    'code' => self::WARRANTY_TYPE_AT_CODE,
                    'title' => self::WARRANTY_TYPE_AT_TITLE
                ],
                [
                    'code' => self::WARRANTY_TYPE_MT_CODE,
                    'title' => self::WARRANTY_TYPE_MT_TITLE
                ]
            ]
        ];
    }

    private static $with = ['type', 'customer.users', 'department.manager', 'qrcode', 'create_user'];

    public static function export()
    {
        $pathPrefix = 'downloads/products/' . date('Y/m/d/');
        $prefix = public_path() . '/' . $pathPrefix;
        $excelFileName = 'products-' . md5(date('YmdHis') . microtime()) . '.xlsx';
        if (!is_dir($prefix)) {
            mkdir($prefix, 0777, true);
        }
        $excelFilePath = $prefix . $excelFileName;
        $spreadsheet = new Spreadsheet();
        $sheet = new Worksheet($spreadsheet, "商品数据");
        $spreadsheet->addSheet($sheet);
        $spreadsheet->removeSheetByIndex(0);

        $excelData = [];
        $excelData[] = [
            '客户编号',
            '*客户',
            '*产品名称',
            '*型号',
            '*出厂编号',
            '*购买日期',
            '服务网点',
            '安装地址/项目地址',
            '质保开始日期',
            '质保结束日期'
        ];

        $productData = self::getProductsForExport();
        $productData = array_merge($excelData, $productData);

        $sheet->fromArray($productData);
        $writer = new Xlsx($spreadsheet);
        $writer->save($excelFilePath);
        return env('APP_URL') . '/' . $pathPrefix . $excelFileName;
    }

    private static function getProductsForExport()
    {
        $builder = Product::query()
            ->select(['c.customer_number', 'c.name as customer_name', 'p.*'])
            ->from('product as p')
            ->join('customer as c', 'c.id', '=', 'p.customer_id');
        $products = $builder->get();
        if (empty($products->count())) {
            return [];
        }
        $result = [];
        foreach ($products as $product) {
            $department = DeptModel::find($product->department_id ?? 0);
            $result[] = [
                $product->customer_number ?? '',
                $product->customer_name ?? '',
                $product->name ?? '',
                $product->model ?? '',
                $product->product_number ?? '',
                $product->date_buy ?? '',
                $department->name ?? '',
                $product->province_name . $product->city_name . $product->county_name . $product->install_address,
                Carbon::parse($product->warranty_start)->toDateString() ?? '',
                Carbon::parse($product->warranty_end)->toDateString() ?? ''
            ];
        }
        return $result;
    }

    public static function getList()
    {
        $perPage = (int)request('limit');
        if ($perPage < 1) {
            $perPage = 1;
        }

        $name = trim(request()->get('name') ?? '');
        $model = trim(request()->get('model') ?? '');
        $filterProject = intval(request()->get('filter_project') ?? '');

        $builder = Product::query();

        if ($name) {
            $builder->where('product.name', 'like', "%{$name}%");
        }
        if ($model) {
            $builder->where('product.model', 'like', "%{$model}%");
        }

        if ($filterProject) {
            $builder->where('product.project_id', 0);
        }

        $builder->orderByDesc('update_time')
            ->orderByDesc('create_time');

        $builder->with(self::$with);

        return $builder->paginate($perPage);
    }

    public static function store($id)
    {
        $data = self::requestData($id);
        $productData = $data['main_data'];
        $ifQrcode = $data['if_qrcode'];
        if ($id) {
            $product = Product::find($id);
        } else {
            $product = new Product();
        }

        if (empty($product)) {
            $product = new Product();
        }

        $product->fill($productData);
        $product->saveOrFail();

        $eventId = $data['event_id'] ?? 0;
        $event = Event::find($eventId);
        if ($event) {
            $event->product_id = $product->id;
            $event->saveOrFail();
        }

        if (!$id && $ifQrcode){
            QrCodeRepo::store(0, ['product_id' => $product->id]);
        }
        return self::fetch($product->id);
    }

    public static function fetch($id)
    {
        $product = Product::with(self::$with)->find($id);
        if (empty($product)) {
            throw new \Exception('商品不存在');
        }
        return $product;
    }

    private static function requestData($id)
    {
        $productData = request()->getContent();
        $productArr = json_decode($productData, true);
        $customerId = intval($productArr['customer_id'] ?? 0);
        $name = trim($productArr['name'] ?? '');
        if (!$name) {
            throw new \Exception('商品名称不能为空');
        }

        $dateBuy = trim($productArr['date_buy'] ?? '');
        $dateCheck = trim($productArr['date_check'] ?? '');
        if (!$dateBuy) {
            throw new \Exception('购买日期必填');
        }

        if (!$dateCheck) {
            // throw new \Exception('验收日期必填');
        }

        $model = trim($productArr['model'] ?? '');
        $attachment = trim($productArr['attachment'] ?? '');
        $typeId = intval($productArr['type_id'] ?? 0);

        // 质保开始时间
        $warrantyStart = $productArr['warranty_start'] ?? $productArr['expiration_start'] ?? '';
        $warrantyStart = Carbon::parse($warrantyStart)->toDateString() . ' 00:00:00';
        // 质保结束时间
        $warrantyEnd = $productArr['warranty_end'] ?? $productArr['expiration_end'] ?? '';
        $warrantyEnd = Carbon::parse($warrantyEnd)->toDateString() . ' 00:00:00';

        $customer = Customer::find($customerId);
        $departmentId = $customer->department_id ?? 0;

        $product = null;
        if ($id) {
            $product = Product::find($id);
        }
        if (!empty($product)) {
            $productNumber = $product->product_number;
        } else {
            $productNumber = self::generateProductNumber();
        }

        $countryId = 0;
        $provinceId = $productArr['province_id'] ?? 0;
        $cityId = $productArr['city_id'] ?? 0;
        $countyId = $productArr['county_id'] ?? 0;

        $countryName = '';
        $province = CityModel::byCityCode($provinceId)->first();
        if (empty($province)) {
            $province = CityModel::find($provinceId);
        }
        $provinceName = $province->name ?? '';

        $city = CityModel::byCityCode($cityId)->first();
        if (empty($city)) {
            $city = CityModel::find($cityId);
        }
        $cityName = $city->name ?? '';

        $county = CityModel::byCityCode($countyId)->first();
        if (empty($county)) {
            $county = CityModel::find($countyId);
        }
        $countyName = $county->name ?? '';

        $address = $productArr['address'] ?? '';

        $installAddress = trim($productArr['install_address'] ?? '');

        $warrantyType = $productArr['warranty_type'] ?? '';
        if (!in_array($warrantyType, [self::WARRANTY_TYPE_MT_CODE, self::WARRANTY_TYPE_AT_CODE])) {
            $warrantyType = self::WARRANTY_TYPE_MT_CODE;
        }

        $ifQrcode = $productArr['if_qrcode'] ?? false;
        $eventId = $productArr['event_id'] ?? 0;

        return [
            'main_data' => [
                'customer_id' => $customerId,
                'type_id' => $typeId,
                'department_id' => $departmentId,
                'product_number' => $productNumber,
                'name' => $name,
                'model' => $model,
                'attachment' => $attachment,
                'country_id' => $countryId,
                'country_name' => $countryName,
                'province_id' => $provinceId,
                'province_name' => $provinceName,
                'city_id' => $cityId,
                'city_name' => $cityName,
                'county_id' => $countyId,
                'county_name' => $countyName,
                'address' => $address,
                'install_address' => $installAddress,
                'date_buy' => $dateBuy,
                'date_check' => $dateCheck,
                'warranty_start' => $warrantyStart,
                'warranty_end' => $warrantyEnd,
                'warranty_type' => $warrantyType
            ],
            'if_qrcode' => $ifQrcode,
            'event_id' => $eventId
        ];
    }

    public static function destroy($id)
    {
        $product = Product::findOrFail($id);
        $qrCode = Product\QrCode::byProductId($id)->first();
        if ($qrCode) {
            self::modifyQrCode($id, $id, 0);
        }
        $product->delete();
    }

    private static function modifyQrCode($id, $trueProductId, $qrCodeId)
    {
        // 绑定二维码
        if ($qrCodeId) {
            $qrCodeData = [
                'product_id' => $trueProductId
            ];
            QrCodeRepo::store($qrCodeId, $qrCodeData);
        }

        // 修改且取消二维码
        if ($id && !$qrCodeId) {
            $qrCode = Product\QrCode::byProductId($id)->first();
            if ($qrCode) {
                $newQrCodeId = $qrCode->id;
                $qrCodeData = [
                    'product_id' => 0
                ];
                QrCodeRepo::store($newQrCodeId, $qrCodeData);
            }
        }
    }

    public static function generateProductNumber($productId = 0)
    {
        $productNumber = date('Ymd') . rand(1000000, 9999900);

        if ($productId) {
            $product = Product::byNumber($productNumber)->first();
            if (!empty($product)) {
                return $product->product_number;
            }
        }

        $productCount = Product::byNumber($productNumber)->count();
        if ($productCount) {
            return self::generateProductNumber();
        }
        return $productNumber;
    }
}